package top.chatgqt.SmartChargeStation.netty.server.websocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * Netty 服务端
 */
@Slf4j
@Component
@Order(1)
public class WebSocketServer implements CommandLineRunner {

    private NioEventLoopGroup bossGroup;
    private NioEventLoopGroup workerGroup;
    private ChannelFuture channelFuture;

    @Value("${Netty.server.port}")
    private int port;

    @Async
    @Override
    public void run(String... args){
        try {
            this.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Netty启动
     */
    private void start() {

        /*
        Netty 对NIO（主从Reactor模型）的深度封装

        1. NioEventLoop 网络指挥官
        2. Channel 通道
        3. ChannelPipline 工作流水线
        4. ChannelHandler 流水线上的员工
        5. ByteBuf 数据容器
         */

        // 处理网络请求
        bossGroup = new NioEventLoopGroup();
        // 处理网络IO
        workerGroup = new NioEventLoopGroup();

        /*
        Bootstrap 中文名称 “引导”
        ServerBootstrap对象的作用是：
            Netty整个程序的组件初始化，启动，服务器连接等等
         */

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap
                // 配置NioEventLoop组件
                .group(bossGroup, workerGroup)
                /*
                SocketChannel 表示：
                    基于Socket通讯的通道
                    监听TCP连接
                 */
                // 配置Channel组件
                .channel(NioServerSocketChannel.class)
                // 配置通道初始化
                .childHandler(new ImoocChannelInit());

        /*
        Netty所有操作都是异步的
        会返回Future对象
        可以利用这个对象可以实现异步操作的通知
         */

        // 绑定服务器直到绑定成功为止
        try {
            // 这个阻塞方法比较短暂，当服务端初始化完成后，阻塞就结束
            channelFuture = bootstrap.bind(port).sync();
            log.info("Netty服务端监听的端口" + port);

            if (channelFuture != null && channelFuture.isSuccess()) {
                log.info(">>>> Netty 服务端启动成功");
            }

            /*
            closeFuture().sync();也是阻塞方法
            这个阻塞方法的作用是：
            将Netty服务端的线程状态设为wait
            那么SpringBoot主线程不会执行finally的方法
             */
            if (channelFuture != null) {
                channelFuture.channel().closeFuture().sync();
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            destroy();
        }
    }


    /**
     * Netty 关闭 释放资源
     */
    @PreDestroy
    private void destroy() {
        try {
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
            // 关闭通道（若已绑定成功）
            channelFuture.channel().close().sync();

            log.info(">>>>  Netty服务器资源已释放");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
